package aduros.game {

import com.whirled.avrg.PlayerSubControlServer;
import com.whirled.net.NetConstants;
import com.whirled.net.PropertySubControl;

/** TODO: Support non-Whirled API stat/badge services. */
public class StatTracker
{
    // Sent to the client, hack because there are no trophy/prize awarded events yet
    public static var MESSAGE_TROPHY :String = "aduros:trophy";
    public static var MESSAGE_PRIZE :String = "aduros:prize";

    public function StatTracker (stats :Object, trophies :Object, ctrl :PlayerSubControlServer)
    {
        _stats = stats;
        _trophies = trophies;
        _ctrl = ctrl;

        _ctrl.doBatch(function () :void {
            for (var statName :String in stats) {
                invalidate(statName);
            }
        });
    }

    /** Awards a trophy, and also sends a metrics signal to the client. */
    public function awardTrophy (ident :String) :Boolean
    {
        if (_ctrl.awardTrophy(ident)) {
            _ctrl.sendMessage(MESSAGE_TROPHY, ident);
            return true;
        } else {
            return false;
        }
    }

    /** Awards a trophy, and also sends a metrics signal to the client. */
    public function awardPrize (ident :String) :void
    {
        _ctrl.awardPrize(ident);
        _ctrl.sendMessage(MESSAGE_PRIZE, ident);
    }

    public function submit (statName :String, value :Object) :void
    {
        if (!(statName in _stats)) {
            throw new Error("Unregistered stat: " + statName);
        }

        _ctrl.doBatch(function () :void {

        var type :int = int(_stats[statName]);
        applySubmit(_ctrl.props, statName, type, value);
        invalidate(statName);

        });
    }

    /** Submits to the a stat without awarding trophies. Handy for calling on offline players. */
    public static function applySubmit (props :PropertySubControl, statName :String, type :int, value :Object) :void
    {
        var statKey :String = NetConstants.makePersistent(statName);
        var current :Object;
        var number :Number = Number(value);

        switch (type) {
            case Stat.ADD:
                if (!isNaN(number) && number != 0) {
                    props.set(statKey, Number(props.get(statKey)) + number, true);
                }
                break;

            case Stat.MAX:
                current = props.get(statKey);
                if (number > current) {
                    props.set(statKey, number, true);
                }
                break;

            case Stat.SET:
                current = props.get(statKey);
                if (value !== current) {
                    props.set(statKey, value, true);
                }
                break;

            default:
                throw new Error("Unsupported stat type: " + type);
        }
    }

    protected function invalidate (statName :String) :void
    {
        var type :int = int(_stats[statName]);
        var statKey :String = NetConstants.makePersistent(statName);
        var current :Object = _ctrl.props.get(statKey);

        if (statName in _trophies) {
            for each (var trophy :Trophy in _trophies[statName] as Array) {

                var elligible :Boolean = false;
                switch (type) {
                    case Stat.ADD:
                    case Stat.MAX:
                        elligible = (current >= trophy.condition);
                        break;

                    case Stat.SET:
                        elligible = (current === trophy.condition);
                        break;
                }

                if (elligible && !_ctrl.holdsTrophy(trophy.id)) {
                    if (awardTrophy(trophy.id) && trophy.prize != null) {
                        awardPrize(trophy.prize);
                    }
                }
            }
        }
    }

    protected var _stats :Object; // statName -> Stat
    protected var _trophies :Object; // statName -> [Trophy]

    protected var _ctrl :PlayerSubControlServer;
}

}
